package com.ruoyi.teaching.service.impl;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.teaching.dto.AddHolidayDetailDTO;
import com.ruoyi.teaching.domain.YaHoliday;
import com.ruoyi.teaching.mapper.YaHolidayMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.teaching.mapper.YaHolidayConfigMapper;
import com.ruoyi.teaching.domain.YaHolidayConfig;
import com.ruoyi.teaching.service.IYaHolidayConfigService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 节假日配置Service业务层处理
 *
 * @author ruoyi
 * @date 2025-02-21
 */
@Service
public class YaHolidayConfigServiceImpl implements IYaHolidayConfigService
{
    // 预期的节假日配置数量
    private static final int EXPECTED_HOLIDAY_COUNT = 7;
    // 年份字符串长度
    private static final int YEAR_LENGTH = 4;
    // 错误提示信息常量
    private static final String ERROR_INVALID_DATA = "节假日配置数据不完整，需要配置7个假期";
    private static final String ERROR_JSON_CONVERSION = "节假日数据转换失败";
    private static final String ERROR_CONFIG_INSERT = "新增节假日配置失败";

    @Autowired
    private YaHolidayConfigMapper yaHolidayConfigMapper;

    @Autowired
    private YaHolidayMapper yaHolidayMapper;

    /**
     * 查询节假日配置
     *
     * @param id 节假日配置主键
     * @return 节假日配置
     */
    @Override
    public YaHolidayConfig selectYaHolidayConfigById(Long id)
    {
        return yaHolidayConfigMapper.selectYaHolidayConfigById(id);
    }

    /**
     * 查询节假日配置列表
     *
     * @param yaHolidayConfig 节假日配置
     * @return 节假日配置列表
     */
    @Override
    public List<YaHolidayConfig> selectYaHolidayConfigList(YaHolidayConfig yaHolidayConfig)
    {
        return yaHolidayConfigMapper.selectYaHolidayConfigList(yaHolidayConfig);
    }

    /**
     * 新增节假日配置
     * 该方法将节假日详情列表保存为配置，并生成具体的节假日记录
     *
     * @param holidayDetailBoList 节假日详情列表
     * @return 插入的节假日数量
     * @throws ServiceException 当数据验证失败或保存失败时
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertYaHolidayConfig(List<AddHolidayDetailDTO> holidayDetailBoList) {
        validateHolidayInput(holidayDetailBoList);

        YaHolidayConfig config = createHolidayConfig(holidayDetailBoList);
        saveHolidayConfig(config);

        List<YaHoliday> holidays = generateHolidayEntries(holidayDetailBoList, config.getId());
        return yaHolidayMapper.batchInsertYaHolidays(holidays);
    }

    /**
     * 验证节假日输入数据的合法性
     * 检查列表是否为空且包含预期数量的节假日配置
     */
    private void validateHolidayInput(List<AddHolidayDetailDTO> holidayDetailBoList) {
        if (CollectionUtils.isEmpty(holidayDetailBoList)
            || holidayDetailBoList.size() != EXPECTED_HOLIDAY_COUNT) {
            throw new ServiceException(ERROR_INVALID_DATA);
        }
    }

    /**
     * 创建节假日配置对象
     * 从输入数据中提取年份并转换为JSON格式
     */
    private YaHolidayConfig createHolidayConfig(List<AddHolidayDetailDTO> holidayDetailBoList) {
        YaHolidayConfig config = new YaHolidayConfig();
        String year = extractYear(holidayDetailBoList.get(EXPECTED_HOLIDAY_COUNT - 1).getDate());
        config.setYear(year);
        config.setContent(convertToJson(holidayDetailBoList));
        return config;
    }

    /**
     * 从日期字符串中提取年份
     * 例如：从 "2023-10-01" 提取 "2023"
     */
    private String extractYear(String date) {
        return date.substring(0, YEAR_LENGTH);
    }

    /**
     * 将节假日详情列表转换为JSON字符串
     * 用于持久化存储
     */
    private String convertToJson(List<AddHolidayDetailDTO> holidayDetailBoList) {
        try {
            return new ObjectMapper().writeValueAsString(holidayDetailBoList);
        } catch (JsonProcessingException e) {
            throw new ServiceException(ERROR_JSON_CONVERSION);
        }
    }

    /**
     * 保存节假日配置到数据库
     * 验证插入操作是否成功
     */
    private void saveHolidayConfig(YaHolidayConfig config) {
        if (yaHolidayConfigMapper.insertYaHolidayConfig(config) != 1) {
            throw new ServiceException(ERROR_CONFIG_INSERT);
        }
    }

    /**
     * 生成具体的节假日记录列表
     * 根据节假日配置生成每一天的具体假期记录
     *
     * @param holidayDetailBoList 节假日详情列表
     * @param configId 配置ID
     * @return 生成的节假日记录列表
     */
    private List<YaHoliday> generateHolidayEntries(List<AddHolidayDetailDTO> holidayDetailBoList, Long configId) {
        List<YaHoliday> holidays = new ArrayList<>();

        for (AddHolidayDetailDTO holidayDetail : holidayDetailBoList) {
            LocalDate currentDate = LocalDate.parse(holidayDetail.getDate());

            for (int i = 0; i < holidayDetail.getCount(); i++) {
                holidays.add(createHolidayEntry(currentDate, configId, holidayDetail.getDescription()));
                currentDate = currentDate.plusDays(1);
            }
        }

        return holidays;
    }

    /**
     * 创建单个节假日记录
     * 设置日期、周几、配置ID和描述信息
     */
    private YaHoliday createHolidayEntry(LocalDate date, Long configId, String description) {
        YaHoliday holiday = new YaHoliday();
        holiday.setDate(date.toString());
        holiday.setWeekday(date.getDayOfWeek().getValue());
        holiday.setConfigId(configId);
        holiday.setDescription(description);
        return holiday;
    }

    /**
     * 修改节假日配置
     *
     * @param yaHolidayConfig 节假日配置
     * @return 结果
     */
    @Override
    public int updateYaHolidayConfig(YaHolidayConfig yaHolidayConfig)
    {
        return yaHolidayConfigMapper.updateYaHolidayConfig(yaHolidayConfig);
    }

    /**
     * 批量删除节假日配置
     *
     * @param ids 需要删除的节假日配置主键
     * @return 结果
     */
    @Override
    public int deleteYaHolidayConfigByIds(Long[] ids)
    {
        return yaHolidayConfigMapper.deleteYaHolidayConfigByIds(ids);
    }

    /**
     * 删除节假日配置信息
     *
     * @param id 节假日配置主键
     * @return 结果
     */
    @Override
    public int deleteYaHolidayConfigById(Long id)
    {
        return yaHolidayConfigMapper.deleteYaHolidayConfigById(id);
    }
}
